#!/bin/bash
#
# Func: Get Process Status In process.cfg

# Define Variables
HOME_DIR="/root/lesson/9.1"
CONFIG_FILE="process.cfg"
#$$表示脚本运行时的pid
this_pid=$$

function get_all_group
{
  G_LIST=$(sed -n '/\[GROUP_LIST\]/,/\[.*\]/p' "$HOME_DIR"/"$CONFIG_FILE" | grep -E -v "(^$|\[.*\])")
  # ^$ 代表空行
  # | 表示或,是扩展的正则表达式,默认不支持(需要使用-E)
  echo "$G_LIST"
}

function get_all_process
{
  for g in $(get_all_group)
  do
    P_LIST=$(sed -n "/\[$g\]/,/\[.*\]/p" "$HOME_DIR"/"$CONFIG_FILE" | grep -E -v "(^$|\[.*\])")
    echo "$P_LIST"
  done
}

function get_process_pid_by_name
{
  # $# 函数中的话代表函数中接受的参数有几个, 脚本中的话代表脚本运行时接受的参数的个数
  if [ $# -ne 1 ];then
    return 1
  else
    # $n 在awk中代表的是这一行的第n个字段
    # 因为脚本执行,本身会生成一个子进程,如果$1是由脚本执行传递进来的,
    # 那么这里脚本执行也会被grep抓到,故这里用 grep -v "$this_pid" 过滤掉了脚本本身
    # $0 代表脚本本身 最好和上面那个一起使用
    pids=$(ps -ef | grep "$1" | grep -v grep | grep -v "$this_pid" | grep -v "$0" | awk '{print $2}')
    echo "$pids"
  fi
}

function get_process_info_by_pid
{
  #awk print命令,后面如果什么都没接,貌似是原样打印整行
  if [ "$(ps -ef | awk -v pid="$1" '$2==pid{print}' | wc -l)" -eq 1 ]; then
    pro_status="RUNNING"
  else
    pro_status="STOPPED"
  fi
  #在shell中,无论是否在函数里,还是在函数外,声明的变量都是全局变量(除非你加local关键字)
  pro_cpu=$(ps aux | awk -v pid="$1" '$2==pid{print $3}')
  pro_mem=$(ps aux | awk -v pid="$1" '$2==pid{print $4}')
  pro_start_time=$(ps -p "$1" -o lstart | grep -v STARTED)
}

function is_group_in_config
{
  for gn in $(get_all_group);do
    # 注意是一个 =
    if [ "$gn" = "$1" ];then
      return
    fi
  done

  echo "Group $1 is not in process.cfg"
  return 1
}

function is_process_in_config
{
  for pn in $(get_all_process);do
    if [ "$pn" = "$1" ];then
      return
    fi
  done

  echo "Process $1 is not in process.cfg"
  return 1
}

function get_all_process_by_group
{

  if is_group_in_config "$1";then
    # ^# 注释掉的也要过滤掉
    p_list=$(sed -n "/\[$1\]/,/\[.*\]/p" "$HOME_DIR"/"$CONFIG_FILE" | grep -E -v "(^$|^#|\[.*\])")
    echo "$p_list"
  else
    echo "GroupName $1 is not in process.cfg"
  fi
}

function get_group_by_process_name
{
  for gn in $(get_all_group);do
    for pn in $(get_all_process_by_group "$gn");do
      if [ "$pn" = "$1" ];then
        echo "$gn"
        return
      fi
    done
  done
}

function format_print
{
  #grep如果没有抓到任何一行,那么返回值是1
  if ps -ef | grep "$1" | grep -v grep | grep -v $this_pid | grep -v "$0" &> /dev/null;then
    pids=$(get_process_pid_by_name "$1")
    for pid in $pids;do
      # 该函数执行后,会多四个全局变量 pro_status pro_cpu pro_mem pro_start_time
      get_process_info_by_pid "$pid"
      awk -v p_name="$1" \
          -v g_name="$2" \
          -v p_pid="$pid" \
          -v p_status="$pro_status" \
          -v p_cpu="$pro_cpu" \
          -v p_mem="$pro_mem" \
          -v p_start_time="$pro_start_time" \
          'BEGIN{printf "%-20s%-12s%-10s%-6s%-7s%-10s%-20s\n",p_name,g_name,p_status,p_pid,p_cpu,p_mem,p_start_time}'
    done
  else
    awk -v p_name="$1" -v g_name="$2" 'BEGIN{printf "%-20s%-12s%-10s%-6s%-7s%-10s%-20s\n",p_name,g_name,"STOPPED","NULL","NULL","NULL","NULL"}'
  fi
}


if [ ! -e "$HOME_DIR"/"$CONFIG_FILE" ];then
  echo "$CONFIG_FILE is not exist... Please Check..."
  exit 1
fi

awk 'BEGIN{printf "%-20s%-10s%-10s%-6s%-7s%-10s%-20s\n","ProcessName---------","GroupName---","Status----","Pid---","CPU---","MEMORY---","StartTime---"}'

if [ $# -gt 0 ];then
  # 列出GroupName组内的所有进程
  # ./app_status.sh -g DB
  if [ "$1" == "-g" ];then
    shift #将-g从$@(参数列表)中移除
    #gn group name
    #pn process name
    for gn in "$@";do
      is_group_in_config "$gn" || continue
      for pn in $(get_all_process_by_group "$gn");do
        is_process_in_config "$pn" && format_print "$pn" "$gn"
      done
    done
  # 列出指定进程的运行信息
  # ./app_status.sh mysql httpd
  else
    for pn in "$@";do
      gn=$(get_group_by_process_name "$pn")
      is_process_in_config "$pn" && format_print "$pn" "$gn"
    done
  fi
# 无参数, 列出配置文件中所有进程的运行信息
else
  for pn in $(get_all_process);do
    gn=$(get_group_by_process_name "$pn")
    is_process_in_config "$pn" && format_print "$pn" "$gn"
  done
fi
